/*****************************************************************************
 * me.h: motion estimation
 *****************************************************************************
 * Copyright (C) 2003-2018 x264 project
 *
 * Authors: Loren Merritt <lorenm@u.washington.edu>
 *          Laurent Aimar <fenrir@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
 *
 * This program is also available under a commercial proprietary license.
 * For more information, contact us at licensing@x264.com.
 *****************************************************************************/

#ifndef X264_ENCODER_ME_H
#define X264_ENCODER_ME_H

#define COST_MAX (1<<28)
#define COST_MAX64 (1ULL<<60)

typedef struct
{
    /* aligning the first member is a gcc hack to force the struct to be aligned,
     * as well as force sizeof(struct) to be a multiple of the alignment. */
    /* input */
    // 搜索范围
    ALIGNED_64( int i_pixel );   /* PIXEL_WxH */
    // 在x264_me_t中，p_cost_mv是一个uint16_t类型的指针，它用于存储每个候选运动矢量的代价。这个指针指向一个内存区域，该区域的大小通常为搜索范围内候选运动矢量的数量。每个候选运动矢量都对应着一个代价，代价的大小表示该矢量与实际的运动矢量（参考矢量）之间的误差大小。通过计算每个候选运动矢量的代价，x264_me_t可以选择最佳的运动矢量，以获得在给定场景下最好的视频质量。
    uint16_t *p_cost_mv; /* lambda * nbits for each possible mv */
    // 在x264_me_t中，i_ref_cost是一个整型变量，用于存储参考帧之间的代价。它是通过比较当前帧与参考帧之间像素的差异计算得到的，差异越大则代价越高，差异越小则代价越低。这个代价值通常被用来选择最佳的参考帧，以便在编码过程中提高视频质量并减少压缩后的数据量。所以，在选择参考帧时，x264_me_t会优先选择代价较小的参考帧，以达到更好的编码效果。
    int      i_ref_cost;
    // 在x264_me_t结构体中，i_ref是一个整型变量，用于表示当前宏块要参考的参考帧索引。具体而言，i_ref用于存储当前宏块所属的参考帧的编号，这个编号通常是从0开始的整数，表示该参考帧在编码过程中出现的顺序。在编码过程中，x264_me_t会根据当前帧的位置以及预测运动矢量和参考块来确定i_ref的值。i_ref的值对于编码过程是非常重要的，因为它决定了参考帧中哪些图像数据可以被用来预测当前宏块中的像素。因此，正确的i_ref值可以最大程度地提高编码效率和视频质量。
    int      i_ref;

    const x264_weight_t *weight;
    /*在x264_me_t结构体中，p_fref[12]是一个pixel类型指针数组，用于存储参考帧的像素数据。这个数组中的每个元素都指向一个大小为图像分辨率的像素数据缓冲区，存储了参考帧的像素数据。具体而言，p_fref[0]表示的是最新的参考帧，而p_fref[1]表示的是次新的参考帧，以此类推，数组中的每个元素表示一个参考帧。这些参考帧通常用于预测当前帧中的宏块的值。

在进行运动估计和编码过程中，x264_me_t将比较当前帧的像素值和参考帧中相应像素的值，以计算运动矢量和编码残差。因此，准确存储参考帧的像素数据对于正确的运动估计和编码非常重要。通过访问p_fref数组，x264_me_t可以快速地获取参考帧的像素数据，以便进行运动估计和编码。*/
    pixel *p_fref[12];
    /*在x264_me_t结构体中，p_fref_w是一个pixel类型的指针，它指向一个大小为w x h 的像素数据缓冲区，存储了当前宏块所在参考帧的像素数据。这个指针通常用于存储最近的、权重最高的参考帧的像素数据。

p_fref_w指向的像素数据缓冲区中，存储了当前宏块所在参考帧的像素数据。在运动估计和编码过程中，p_fref_w用于计算当前宏块的预测像素值，通过计算当前宏块和参考块之间的像素差异，来选择合适的运动矢量。通过访问p_fref_w指针，x264_me_t可以快速地获取参考帧的像素数据，以便进行运动估计和编码。因为p_fref_w只存储当前帧上预测当前宏块所使用的参考帧，所以它在内存占用上比p_fref数组要小。*/
    pixel *p_fref_w;
    // 编码帧，y/u/v分量
    pixel *p_fenc[3];
    // 积分图
    /*在x264_me_t结构体中，integral是一个uint16_t类型的指针，它指向一个大小为(w+1)x(h+1)的积分图。积分图保存了视频帧中所有方块的灰度值的累计和，用于实现快速的图像遮罩计算。

在运动估计过程中，x264_me_t使用积分图来计算目标宏块与参考宏块之间的代价。因为积分图保存了所有方块的灰度值的总和，所以通过对两个宏块之间的积分值进行简单的减法，就可以得到两个宏块之间的代价。积分图在运动估计过程中是必需的，因为它可以提供比对通常游程长度限制更高的代价精度。

integral指向的内存区域可以被看做是一个二维数组，其中第i行第j列的元素表示从图像左上角到(i,j)这个像素位置的所有像素的灰度值之和。这个数组的大小比图像的实际大小要大一行一列，这是为了避免计算坐标时的越界问题。*/
    uint16_t *integral;
    int      i_stride[3];

    // 预测的mv
    /*在x264_me_t结构体中，mvp[2]是一个大小为2的数组，其中存储了当前宏块的运动矢量的预测值。这个数组通常被称为运动矢量预测器（Motion Vector Predictor，MVP）。

在运动估计过程中，x264_me_t首先通过搜索参考块来找到最优的运动矢量，然后使用MVP对该运动矢量进行预测。这个预测值通常是通过在当前宏块周围的相邻块中寻找运动矢量并计算平均值来计算得到的。

预测值具有很大的意义，它可以降低计算复杂度、提升运动矢量搜索的精度和准确性等等。在编码过程中，精准的运动矢量可以显著提升帧内/帧间编码的效率，并且保证编码后视频质量的稳定性和一致性。*/
    ALIGNED_4( int16_t mvp[2] );

    /* output */
    /*在x264_me_t结构体中，cost_mv是一个整型变量，表示当前运动矢量与参考矢量之间的代价。在运动估计过程中，x264_me_t通过计算参考块与当前宏块之间的像素差异来计算每个候选运动矢量的代价，并选择代价最小的运动矢量作为最优运动矢量。cost_mv用于存储当前候选运动矢量的代价，以便在比对候选运动矢量时，可以比较不同运动矢量的代价大小，从而选择代价最小的运动矢量。

在计算cost_mv时，x264_me_t通常会根据参考块和当前宏块的像素值差异计算代价。因此，cost_mv的值较小就代表当前候选运动矢量的像素差异较小，与参考宏块的相似度较高，同时它在这个位置上则更有可能成为最优的运动矢量。*/
    int cost_mv;        /* lambda * nbits for the chosen mv */
    /*在x264_me_t结构体中，cost是一个整型变量，用于存储当前运动矢量与参考宏块之间的代价。在运动估计过程中，x264_me_t通过比较参考块和当前宏块之间的像素差异，计算每个候选运动矢量的代价，并选择代价最小的运动矢量作为最优运动矢量。cost变量的值用于存储当前最优运动矢量的代价，以便在编码过程中可以使用该运动矢量来压缩和重建视频帧。

在计算cost时，x264_me_t通常会根据参考块和当前宏块的像素值差异计算代价。因此，cost的值较小代表当前最优运动矢量是像素差异最小的运动矢量，从而在编码过程中可以减少编码残差，提高图像质量。*/
    int cost;           /* satd + lambda * nbits */
    /*在x264_me_t结构体中，mv[2]是一个大小为2的数组，用于存储当前最佳运动矢量。在运动估计过程中，x264_me_t通过比较参考块和当前宏块之间的像素差异计算每个候选运动矢量的代价，并选择代价最小的运动矢量作为最优运动矢量。然后，最优运动矢量存储在mv数组中。mv数组通常由两个元素组成，分别代表运动矢量在水平和竖直方向上的分量。这个最优运动矢量用于在编码过程中预测当前宏块的像素值，并用于计算编码残差。

具体而言，mv数组中的元素表示运动矢量在水平和竖直方向上的垂直分量和水平分量。它通常用于表示当前宏块相对于参考块的移动量，也称为运动向量。mv数组的值是在运动估计过程中计算出来的，它可以帮助x264_me_t预测当前宏块中的像素值，并在编码过程中计算编码残差。*/
    ALIGNED_4( int16_t mv[2] );
} ALIGNED_64( x264_me_t );

#define x264_me_search_ref x264_template(me_search_ref)
void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, int *p_fullpel_thresh );
#define x264_me_search( h, m, mvc, i_mvc )\
    x264_me_search_ref( h, m, mvc, i_mvc, NULL )

#define x264_me_refine_qpel x264_template(me_refine_qpel)
void x264_me_refine_qpel( x264_t *h, x264_me_t *m );
#define x264_me_refine_qpel_refdupe x264_template(me_refine_qpel_refdupe)
void x264_me_refine_qpel_refdupe( x264_t *h, x264_me_t *m, int *p_halfpel_thresh );
#define x264_me_refine_qpel_rd x264_template(me_refine_qpel_rd)
void x264_me_refine_qpel_rd( x264_t *h, x264_me_t *m, int i_lambda2, int i4, int i_list );
#define x264_me_refine_bidir_rd x264_template(me_refine_bidir_rd)
void x264_me_refine_bidir_rd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight, int i8, int i_lambda2 );
#define x264_me_refine_bidir_satd x264_template(me_refine_bidir_satd)
void x264_me_refine_bidir_satd( x264_t *h, x264_me_t *m0, x264_me_t *m1, int i_weight );
#define x264_rd_cost_part x264_template(rd_cost_part)
uint64_t x264_rd_cost_part( x264_t *h, int i_lambda2, int i8, int i_pixel );

#define COPY1_IF_LT(x,y)\
if( (y) < (x) )\
    (x) = (y);

#define COPY2_IF_LT(x,y,a,b)\
if( (y) < (x) )\
{\
    (x) = (y);\
    (a) = (b);\
}

#define COPY3_IF_LT(x,y,a,b,c,d)\
if( (y) < (x) )\
{\
    (x) = (y);\
    (a) = (b);\
    (c) = (d);\
}

#define COPY4_IF_LT(x,y,a,b,c,d,e,f)\
if( (y) < (x) )\
{\
    (x) = (y);\
    (a) = (b);\
    (c) = (d);\
    (e) = (f);\
}

#define COPY2_IF_GT(x,y,a,b)\
if( (y) > (x) )\
{\
    (x) = (y);\
    (a) = (b);\
}

#endif
